'''
    pyPopeye_channel: Where actual things are done
'''

import channel
import pyPopeye_access

import regexes
import datetime
import time
import re
import shelve
import weakref

class ReloadMe(Exception):
    pass

def access(levelname):
    def decorator(fn):
        def _access(self, msg):
            ulevel = 'admin' if (msg.nick in ['[iX]Steve', 'EmperorSteve', '[steve]']) else 'user'
            if ulevel == levelname:
                return fn(self, msg)
        return _access
    return decorator

class pyPopeye_channel(channel.channel):
    msglog = []
    ftpinfo = None
    
    class Responder(object):
        sigil = '@'
        
        def __init__(self, chan):
            self._c = weakref.ref(chan)
            self._s = chan.server_weakref
        
        def reload(self, msg=None):
            ''' Reload the channel module, to change behavior '''
            raise ReloadMe
                
        def hello(self, msg):
            ''' Say hello to the speaker '''
            print >>self._c(), "Hello, %s" % msg.nick
            
        def join(self, msg):
            ''' Join another channel '''
            s = msg.message.split()[1]
            self._s().channels.append(pyPopeye_channel(self._s, s))

        def part(self, msg):
            ''' Part this channel '''
            s = msg.message.split()[1]
            self._s().get_chan_by_name(s).part('Good riddance!')

        def say(self, msg):
            ''' Say something on the channel '''
            print >>self._c(), "%s says: %s" % (msg.nick, msg.message)
            
        def seen(self, msg):
            ''' Find when a user last spoke, where, and what '''
            n = msg.message.split()[1]
            try:
                print >>self._c(), n + " last spoke at %s on %s: %s" % self._c().server_weakref().seen_list[n]
            except:
                print >>self._c(), "Haven't seen " + n
        
        @access('admin')
        def eval_(self, msg):
            ''' Do raw stuff.  Dangerous.  But broken. '''
            cmd = msg.message[len(self.sigil + 'eval_ '):]
            print >>self._c(), "eval(\"%s\") = %s" % (cmd, eval(cmd))

        @access('admin')
        def exec_(self, msg):
            ''' Do raw stuff.  Dangerous.  But broken. '''
            cmd = msg.message[len(self.sigil + 'exec_ '):]
            print >>self._c(), cmd
            exec(cmd)

        def dir(self, msg):
            ''' Find available functions '''
            fns = [i for i in dir(self) if (not (i.startswith('_'))
                                  and callable(getattr(self, i)))]
            for i in fns:
                print >>self._c(), '%s%s - %s' % (self.sigil, i,
                            (getattr(self, i).__doc__ or '').strip())
        
        def __call__(self, msg):
            s = msg.message.split()[0]
            if s.startswith(self.sigil):
                getattr(self, s[1:], lambda x: None)(msg)

    def __init__(self, server, chan_name, softjoin=0):
        channel.channel.__init__(self, server, chan_name, softjoin)
        
        self.r = pyPopeye_channel.Responder(self)
        
        #Wonderful hack - make the server object keep track of seen
        #users, but only when using the pyPopeye channel
        if not getattr(server(), 'seen_list', False):
            setattr(server(), 'seen_list', shelve.open('seen.' + server().server_host, protocol=-1))


    def write(self, data):
        assert self.server_weakref() is not None, 'Server connection is dead!'
        if data == '\n':
            return
        channel.channel.write(self, data)
        curtime = datetime.datetime.now().strftime('%d %b [%H:%M:%S]')
        message_line = '%s <%s> %s' % (curtime, self.server_weakref().conn_info['nick'], data)
        print self.chan_name, message_line
        self.msglog += [message_line]

    def on_join(self, name):
        channel.channel.on_join(self, name)
        
        msg = '%s joined %s' % (name, self.chan_name)
        self.msglog.append(msg)
        print msg
        
    def on_part(self, name, reason = None):
        channel.channel.on_part(self, name, reason)
        if reason is None:
            reason = 'No reason given'
        msg = '%s left %s (%s)' % (name, self.chan_name, reason)
        self.msglog.append(msg)
        print msg
    
    def on_quit(self, name, reason = None):
        channel.channel.on_part(self, name, reason)
        if reason is None:
            reason = 'No reason given'
        msg = '%s has quit IRC (%s)' % (name, reason)
        self.nicks.remove(name)
    
    def on_nick(self, nick, newnick):
        return channel.channel.on_nick(self, nick, newnick)
    
    def on_kick(self, nick):
        channel.channel.on_kick(self, nick)
        
        print '%s was kicked from %s' % (nick, self.chan_name)
        
    def raw_callback(self, data):
        print >> self, data

    def on_msg(self, msg):
        try:
            self.r(msg)
            self._see(msg)
            print "[%s] <%s> %s" % (msg.channel, msg.nick, msg.message)
        except Exception, e:
            print "[ERROR] Exception raised: %s" % str(e)
            print >>self, "Reloading due to error"
            self.server_weakref().dynamic_reload()

    def _see(self, msg):
        self.server_weakref().seen_list[msg.nick] = (time.ctime(), self.chan_name, msg.message)
